`timescale 1ns / 1ps
//////////////////////////////////////////////////////////////////////////////////
// Company: 
// Engineer: 
// 
// Create Date:    18:07:44 05/28/2013 
// Design Name: 
// Module Name:    BoardConfiguration 
// Project Name: 
// Target Devices: 
// Tool versions: 
// Description: 
//
// Dependencies: 
//
// Revision: 
// Revision 0.01 - File Created
// Additional Comments: 
//
//////////////////////////////////////////////////////////////////////////////////
/* This configuration:
    MMIO0 = Leds
    MMIO1 = Switches
    MMIO2 = Hex7Segs
    MMIO3 = PS2Keyboard
    MMIO4 = Servo
    MMIO5 = HexKeypad
    MMIO6 = StepperMotor
    MMIO7 = StaticOscillator
*/
module BoardConfiguration(
    input clk_50,
    output [7:0] leds,
    input [7:0] switches,
    input [3:0] pButtons,
    output [6:0] segDisplaySegs,
    output segDisplayDot,
    output [3:0] segDisplaySelector,
    inout [7:0] JA,
    inout [7:0] JB,
    inout [7:0] JC,
    input EppAstb,
    input EppDstb,
    input EppWR,
    output EppWait,
    inout [7:0] EppDB,
    inout PS2D,
    inout PS2C
    );
	
	wire [83:72] PIO; //board PMOD ports
	
	//board Specific Remap;
	assign JA = PIO[79:72];
	assign JB[3:0] = PIO[83:80];
	assign JB[7:4] = 4'b0;
	//clock wires
	wire clk_25;
	wire clk_12p5;
	
	ClockDivider #(3) clkDiv(clk_100, {clk_12p5, clk_25, clk_50});
	
	//reset wires
	wire reset = pButtons[0];
	wire CPU_Master_Reset;
	    
	//instatiation of Board Interface
	wire [1:0] mode;
	wire [0:0] debug_cpu_clks;
	wire [3:0] memorySelector;
	wire [31:0] BI_MemorySize;
	wire [31:0] BI_MEM_Address;
	wire [31:0] BI_Mem_Out;
	wire BI_Mem_Done;
	wire [31:0] BI_Mem_DataIn;
	wire BI_MEM_Write;
	wire [3:0] cpuSelector;
	wire [7:0] cpuFrequency;
	wire [31:0] cpuPC;
	wire [4:0] cpuRegisterSelector;
	wire [31:0] cpuRegisterValue;
	
	BoardInterface #(1, 1) BoardInterfaceInstance(clk_50, reset,
	mode, pButtons[1],
	debug_cpu_clks,
	EppAstb, EppDstb, EppWR, EppWait, EppDB, //EPP wires
	memorySelector, BI_MemorySize, BI_MEM_Address, BI_Mem_Out, BI_Mem_Done, BI_Mem_DataIn, BI_MEM_Write,
	cpuSelector, cpuFrequency, cpuPC, cpuRegisterSelector, cpuRegisterValue);
	
	
	//instatiation of SevenSeg Hardware Basic
	reg [3:0] sevenSegEnables;
	reg [15:0] sevenSegData;
	reg [3:0] sevenSegDots;
	SevenSeg debuggerSeg(clk_50,
	 sevenSegEnables,
    sevenSegData[3:0],
    sevenSegData[7:4],
    sevenSegData[11:8],
	 sevenSegData[15:12],
	 sevenSegDots,
	 segDisplaySegs,
	 segDisplayDot,
	 segDisplaySelector
    );
	//other wire defs
	parameter MODE_PC_DOWNLOADER = 2'b00;
	parameter MODE_UNKNOWN = 2'b01;
	parameter MODE_DEBUG = 2'b10;
	parameter MODE_RUN = 2'b11;
	
	
	
	assign CPU_Master_Reset = (mode == MODE_PC_DOWNLOADER) ? 1 : 0;
	
	wire clk_cpu0 = clk_25;
	wire CPU_0_Reset = pButtons[0];
	

	
	//MEM_HEADER_WIRES
	
	/////// MEMORY 1 ////////
	
	wire [31:0] MEM1_Address1;
	wire [31:0] MEM1_DataOut1;
	wire [31:0] MEM1_DataIn1;
	wire MEM1_Write1;
	wire MEM1_Ack1 = 1;
	wire [31:0] MEM1_Address2;
	wire [31:0] MEM1_DataOut2;
	wire [31:0] MEM1_DataIn2;
	wire MEM1_Write2 = 0;
	wire MEM1_Ack2 = 1;
	wire MEM1_Address1_Invalid = |MEM1_Address1[31:10];
	wire MEM1_Address2_Invalid = |MEM1_Address2[31:10];
	
	
	DISMEM32w256d simpleMemory (
  MEM1_Address1[9:2], // input [7 : 0] a
  MEM1_DataIn1, // input [31 : 0] d
  MEM1_Address2[9:2], // input [7 : 0] dpra
  mclk, // input clk
  MEM1_Write1, // input we
  MEM1_DataOut1, // output [31 : 0] spo
  MEM1_DataOut2 // output [31 : 0] dpo
);

	//this is a memory output selector for the Board Interface Module
	reg BI_Mem_DoneReg;
	 reg [31:0] BI_Mem_OutReg;
	 assign BI_Mem_Done = BI_Mem_DoneReg;
	 assign BI_Mem_Out = BI_Mem_OutReg;
	 always @(*) begin
		case(memorySelector)
			4'd0: begin
				BI_Mem_OutReg = MEM1_DataOut1;
				BI_Mem_DoneReg = MEM1_Ack1;
			end
			default: begin
				BI_Mem_OutReg = 32'b0;
				BI_Mem_DoneReg = 1;
			end
		endcase
	 end
	
	//Controller Definitions
	
	//On-Board Led Controller
	wire        OBLC_Enable;
	wire  [3:0] OBLC_Address;
	wire [31:0] OBLC_DataIn;
	wire [31:0] OBLC_DataOut;
	wire        OBLC_Write;
	wire        OBLC_Done;
	wire        OBLC_Interrupt;
	
	OnBoardLedController OBLC_Instance(mclk, reset, OBLC_Enable, OBLC_Address, OBLC_DataIn, OBLC_DataOut, OBLC_Write, OBLC_Done, OBLC_Interrupt, leds);
	 
	//On-Board Switches Controller
	wire        OBSWC_Enable;
	wire  [3:0] OBSWC_Address;
	wire [31:0] OBSWC_DataIn;
	wire [31:0] OBSWC_DataOut;
	wire        OBSWC_Write;
	wire        OBSWC_Done;
	wire        OBSWC_Interrupt;
	
	OnBoardSwitchesController OBSWC_Instance(mclk, reset, OBSWC_Enable, OBSWC_Address, OBSWC_DataIn, OBSWC_DataOut, OBSWC_Write, OBSWC_Done, OBSWC_Interrupt, switches);
	
	//On-Board 7 Seg Hex Controller
	wire        OBSSC_Enable;
	wire  [3:0] OBSSC_Address;
	wire [31:0] OBSSC_DataIn;
	wire [31:0] OBSSC_DataOut;
	wire        OBSSC_Write;
	wire        OBSSC_Done;
	wire        OBSSC_Interrupt;
	
	wire  [3:0] OBSSC_digitEnables;
	wire [15:0] OBSSC_data;
	wire  [3:0] OBSSC_dots;
	
	OnBoard7SegHexController OBSS_Instance(mclk, reset, OBSSC_Enable, OBSSC_Address, OBSSC_DataIn, OBSSC_DataOut, OBSSC_Write, OBSSC_Done, OBSSC_Interrupt, OBSSC_digitEnables, {OBSSC_dots, OBSSC_data});
	
/*	
	wire OFBSERC_Enable;
	wire [3:0] OFBSERC_Address;
	wire [31:0] OFBSERC_DataIn;
	wire [31:0] OFBSERC_DataOut;
	wire OFBSERC_Write;
	wire OFBSERC_Done;
	wire OFBSERC_Interrupt;
	
	PmodCON3Controller OFBSERC_Instance(mclk, reset, OFBSERC_Enable, OFBSERC_Address, OFBSERC_DataIn, OFBSERC_DataOut, OFBSERC_Write, OFBSERC_Done, OFBSERC_Interrupt, clk_50, PIO[83:80]); 
	
	wire OBKBC_Enable;
	wire [3:0] OBKBC_Address;
	wire [31:0] OBKBC_DataIn;
	wire [31:0] OBKBC_DataOut;
	wire OBKBC_Write;
	wire OBKBC_Done;
	wire OBKBC_Interrupt;
	
	PS2KeyboardController OBKBC_Instance(mclk, reset, OBKBC_Enable, OBKBC_Address, OBKBC_DataIn, OBKBC_DataOut, OBKBC_Write, OBKBC_Done, OBKBC_Interrupt, clk_50, PS2C, PS2D);
*/	
	// External Hex Keypad Controller (attached to JC)
	wire        EHK_Enable;
	wire  [3:0] EHK_Address;
	wire [31:0] EHK_DataIn;
	wire [31:0] EHK_DataOut;
	wire        EHK_Write;
	wire        EHK_Done;
	wire        EHK_Interrupt;
	
	HexKeypadController EHK_Instance(mclk, reset, EHK_Enable, EHK_Address, EHK_DataIn, EHK_DataOut, EHK_Write, EHK_Done, EHK_Interrupt, JC);

	// External Stepper Motor Controller (attached to JA)
	wire        ESM_Enable;
	wire  [3:0] ESM_Address;
	wire [31:0] ESM_DataIn;
	wire [31:0] ESM_DataOut;
	wire        ESM_Write;
	wire        ESM_Done;
	wire        ESM_Interrupt;
	
	StepperMotorController ESM_Instance(mclk, reset, ESM_Enable, ESM_Address, ESM_DataIn, ESM_DataOut, ESM_Write, ESM_Done, ESM_Interrupt, JB);
/*	
	// External IS2 Static Oscillator Controller (attached to JB[3:0])
	wire I2SSO_Enable;
	wire [3:0] I2SSO_Address;
	wire [31:0] I2SSO_DataIn;
	wire [31:0] I2SSO_DataOut;
	wire I2SSO_Write;
	wire I2SSO_Done;
	wire I2SSO_Interrupt;
	
	StaticOscillatorController I2SSO_Instance(mclk, reset, I2SSO_Enable, I2SSO_Address, I2SSO_DataIn, I2SSO_DataOut, I2SSO_Write, I2SSO_Done, I2SSO_Interrupt, JB[7:4]);
*/

	///***************** SYSTEM DEFINITIONS ******************* ///
	
	/// ###################### SYS1 ########################### ///
	
	//SYSTEM 1 Bus Wire Definitions
	wire [31:0] SYS1_InstructionBus_Address;
	wire [31:0] SYS1_InstructionBus_Data;
	wire SYS1_InstructionBus_InvalidAddress = MEM1_Address2_Invalid;
	wire SYS1_InstructionBus_Ack;
	wire [31:0] SYS1_DataBus_Address;
	wire [31:0] SYS1_DataBus_DataFromCPU;
	wire [31:0] SYS1_DataBus_DataToCPU;
	wire SYS1_DataBus_InvalidAddress;
	wire SYS1_DataBus_Write;
	
	wire SYS1_DataBus_Ack;
	
	wire [15:0] SYS1_IOEnables;
	wire [15:0] SYS1_Interrupts;
	
	wire SYS1_DataBus_MMIO = &SYS1_DataBus_Address[31:16];
	
	wire cpu0_clk;
	wire cpu0_reset;
	
	//START SYSTEM 1 LOGIC
	wire SYS1_DataBus_Read;
	 
	
	 //ignored always reading unless writing
	
	/*BusStimulator myStimulator(clk_cpu0,
	CPU_0_Reset | CPU_Master_Reset,
	SYS1_InstructionBus_Address,
	SYS1_InstructionBus_Data,
	SYS1_InstructionBus_Ack,
	SYS1_DataBus_Write,
	SYS1_DataBus_Read,
	SYS1_DataBus_Ack,
	SYS1_DataBus_Address,
	SYS1_DataBus_DataFromCPU,
	SYS1_DataBus_DataToCPU,
	SYS1_Interrupts,
	//extras not required for real cpu instance
	pButtons[1],
	pButtons[2],
	,
	{dots, sevenSegData}
	);*/
	
	reg [31:0] MEM1_Address1Reg;
	reg [31:0] MEM1_DataIn1Reg;
	reg MEM1_Write1Reg;
	reg cpu0_clkReg;
	assign MEM1_Address1 = MEM1_Address1Reg;
	assign MEM1_DataIn1 = MEM1_DataIn1Reg;
	assign MEM1_Write1 = MEM1_Write1Reg;
	assign cpu0_clk = cpu0_clkReg;
	
	always @(*) begin
		case (mode)
			MODE_PC_DOWNLOADER: begin
				MEM1_Address1Reg = (memorySelector == 4'b0) ? BI_MEM_Address : 32'b0;
				MEM1_DataIn1Reg = (memorySelector == 4'b0) ? BI_Mem_DataIn : 32'b0;
				MEM1_Write1Reg = (memorySelector == 4'b0) ? BI_MEM_Write : 0;
				cpu0_clkReg = 0;
			end
			MODE_UNKNOWN: begin
				MEM1_Address1Reg = {22'b0, switches, 2'b0};
				MEM1_DataIn1Reg = 32'b0;
				MEM1_Write1Reg = 0;
				cpu0_clkReg = 0;
			end
			MODE_DEBUG: begin
				MEM1_Address1Reg = (SYS1_DataBus_MMIO ? 32'b0 : SYS1_DataBus_Address);
				MEM1_DataIn1Reg = SYS1_DataBus_DataFromCPU;
				MEM1_Write1Reg = ~SYS1_DataBus_MMIO & SYS1_DataBus_Write;
				cpu0_clkReg = debug_cpu_clks[0];
			end
			MODE_RUN: begin
				MEM1_Address1Reg = (SYS1_DataBus_MMIO ? 32'b0 : SYS1_DataBus_Address);
				MEM1_DataIn1Reg = SYS1_DataBus_DataFromCPU;
				MEM1_Write1Reg = ~SYS1_DataBus_MMIO & SYS1_DataBus_Write;
				cpu0_clkReg = clk_12p5; //setting the default run speed of cpu 0 to 25mhz
			end
		endcase
	end
	
	assign MEM1_Address2 = SYS1_InstructionBus_Address;
	assign SYS1_InstructionBus_Data = MEM1_DataOut2;
	assign SYS1_InstructionBus_Ack = MEM1_Ack2;
	

	

	
	mips cpu_instance(cpu0_clk,
	CPU_0_Reset | CPU_Master_Reset,
	SYS1_InstructionBus_Address,
	SYS1_InstructionBus_Data,
	SYS1_InstructionBus_Ack,
   SYS1_InstructionBus_InvalidAddress, // InstrInvalidAddressF
	SYS1_DataBus_Write,
	SYS1_DataBus_Read,
	SYS1_DataBus_Ack,
   SYS1_DataBus_InvalidAddress, // DataInvalidAddressM
	SYS1_DataBus_Address,
	SYS1_DataBus_DataFromCPU,
	SYS1_DataBus_DataToCPU,
	SYS1_Interrupts,
	cpuRegisterSelector,
	cpuRegisterValue
	);
	
	

	 wire [7:0]segData = ~pButtons[1] ? SYS1_InstructionBus_Address[7:0] : SYS1_InstructionBus_Data[7:0];
	 
	 PmodSSD debugger2(clk_50, segData[7:4],
    segData[3:0], PIO[78:72], PIO[79]);
	
	IRQDecoder SYS1EnableMux(SYS1_DataBus_MMIO, SYS1_DataBus_Address[9:6], SYS1_IOEnables);
	
	//Assigning all Memory Mapped IO Wires
	assign OBLC_DataIn  = SYS1_DataBus_DataFromCPU;
	assign OBLC_Enable  = SYS1_IOEnables[0];
	assign OBLC_Address = SYS1_DataBus_Address[5:2];
	assign OBLC_Write   = SYS1_DataBus_Write;
	
	assign OBSWC_DataIn  = SYS1_DataBus_DataFromCPU;
	assign OBSWC_Enable  = SYS1_IOEnables[1];
	assign OBSWC_Address = SYS1_DataBus_Address[5:2];
	assign OBSWC_Write   = SYS1_DataBus_Write;
	
	assign OBSSC_DataIn  = SYS1_DataBus_DataFromCPU;
	assign OBSSC_Enable  = SYS1_IOEnables[2];
	assign OBSSC_Address = SYS1_DataBus_Address[5:2];
/*
	assign OBKBC_DataIn = SYS1_DataBus_DataFromCPU;
	assign OBKBC_Enable = SYS1_IOEnables[3];
	assign OBKBC_Address = SYS1_DataBus_Address[5:2];
	assign OBKBC_Write = SYS1_DataBus_Write;
	
	assign OFBSERC_DataIn = SYS1_DataBus_DataFromCPU;
	assign OFBSERC_Enable = SYS1_IOEnables[4];
	assign OFBSERC_Address = SYS1_DataBus_Address[5:2];
	assign OFBSERC_Write = SYS1_DataBus_Write;
*/	
	assign EHK_DataIn = SYS1_DataBus_DataFromCPU;
	assign EHK_Enable = SYS1_IOEnables[3];
	assign EHK_Address = SYS1_DataBus_Address[5:2];
	assign EHK_Write = SYS1_DataBus_Write;

	assign ESM_DataIn  = SYS1_DataBus_DataFromCPU;
	assign ESM_Enable  = SYS1_IOEnables[4];
	assign ESM_Address = SYS1_DataBus_Address[5:2];
	assign ESM_Write   = SYS1_DataBus_Write;
/*	
	assign I2SSO_DataIn = SYS1_DataBus_DataFromCPU;
	assign I2SSO_Enable = SYS1_IOEnables[7];
	assign I2SSO_Address = SYS1_DataBus_Address[5:2];
	assign I2SSO_Write = SYS1_DataBus_Write;
*/
	//16 bit interrupt bus assignment
	assign SYS1_Interrupts = {11'b0, ESM_Interrupt, EHK_Interrupt, OBSSC_Interrupt, OBSWC_Interrupt, OBLC_Interrupt};
	
	//Controller & memory to data bus selector
	reg [31:0] S1_DBD;

	reg S1_DBDone;
	reg SYS1_DataBus_InvalidAddress_reg;
	always @ (*) begin
		if(SYS1_DataBus_MMIO) begin
			case(SYS1_DataBus_Address[9:6])
				4'd0: begin
					S1_DBD = OBLC_DataOut;
					S1_DBDone = OBLC_Done;
					SYS1_DataBus_InvalidAddress_reg = 1'b0;
					end
				4'd1: begin
					S1_DBD = OBSWC_DataOut;
					S1_DBDone = OBSWC_Done;
					SYS1_DataBus_InvalidAddress_reg = 1'b0;
					end
				4'd2: begin
					S1_DBD = OBSSC_DataOut;
					S1_DBDone = OBSSC_Done;
					SYS1_DataBus_InvalidAddress_reg = 1'b0;
					end
/*				4'd3: begin
					S1_DBD = OBKBC_DataOut;
					S1_DBDone = OBKBC_Done;
					SYS1_DataBus_InvalidAddress_reg = 1'b0;
					end
				4'd4: begin
					S1_DBD = OFBSERC_DataOut;
					S1_DBDone = OFBSERC_Done;
					SYS1_DataBus_InvalidAddress_reg = 1'b0;
					end
*/				4'd3: begin
					S1_DBD = EHK_DataOut;
					S1_DBDone = EHK_Done;
					SYS1_DataBus_InvalidAddress_reg = 1'b0;
					end
				4'd4: begin
					S1_DBD = ESM_DataOut;
					S1_DBDone = ESM_Done;
					SYS1_DataBus_InvalidAddress_reg = 1'b0;
					end
/*				4'd7: begin
					S1_DBD = I2SSO_DataOut;
					S1_DBDone = I2SSO_Done;
					SYS1_DataBus_InvalidAddress_reg = 1'b0;
					end
*/				default: begin
					S1_DBD = 32'b0;
					S1_DBDone = 1'b1;
					SYS1_DataBus_InvalidAddress_reg = 1'b1;
					end
			endcase
		end
		else begin
			S1_DBD = MEM1_DataOut1;
			S1_DBDone = MEM1_Ack1;
			SYS1_DataBus_InvalidAddress_reg = MEM1_Address2_Invalid;
		end
	end
	
	assign SYS1_DataBus_DataToCPU = S1_DBD;
	assign SYS1_DataBus_Ack = S1_DBDone;
	assign SYS1_DataBus_InvalidAddress = SYS1_DataBus_InvalidAddress_reg;
	
	//END SYSTEM 1 Logic
	
	parameter CON_CPU_NUM = 1;
	parameter CON_MEM_NUM = 1;
	 
	parameter CPU_NUM = 4'd1;
	parameter MEM_NUM = 4'd1;
	 
	 // CPU FREQUENCY CONSTANTS ROM
	 
	 reg [7:0] cpu_frequency;
	 reg [31:0] cpu_PCReg;
	 assign cpuFrequency = cpu_frequency;
	 assign cpuPC = cpu_PCReg;
	 always @(*) begin
		case(cpuSelector)
			4'd0: begin
				cpu_frequency = 8'd1;
				cpu_PCReg = SYS1_InstructionBus_Address;
				end				
			default: begin
				cpu_frequency = 8'd0;
				cpu_PCReg = 32'b0;
				end
		endcase
	 end
	
	// Memory Size CONSTANTS ROM
	 
	 reg [31:0] mem_size;
	 assign BI_MemorySize = mem_size;
	 always @(*) begin
		case(memorySelector)
			4'd0: mem_size = 32'd256;
			default: mem_size = 32'd0;
		endcase
	 end
	 
	wire [15:0] databw = ~pButtons[3] ? SYS1_DataBus_DataFromCPU[15:0] : SYS1_DataBus_DataFromCPU[31:16];
	wire [15:0] databr = ~pButtons[3] ? SYS1_DataBus_DataToCPU[15:0] : SYS1_DataBus_DataToCPU[31:16];
	wire [15:0] datab = SYS1_DataBus_Write ? databw : databr;
	
	//shows data adress normally
	//pressing btn3 shows up half of data
	//pressing btn1 shows data
	 
	 //7Seg switcher for debugger
	always @(*) begin
		if(mode[1]) begin// if in debugger or run mode
			sevenSegEnables = OBSSC_digitEnables; //(mode[0]) ? OBSSC_digitEnables : 4'b1111;
			sevenSegData = OBSSC_data;//(mode[0]) ? OBSSC_data : (~(pButtons[1]) ? (~pButtons[3] ? SYS1_DataBus_Address[15:0] : SYS1_DataBus_Address[31:16]) : datab);
			sevenSegDots[3:2] = OBSSC_dots[3:2]; //(mode[0]) ? OBSSC_dots[3:2] : {SYS1_DataBus_Write, SYS1_DataBus_MMIO};
         sevenSegDots[1:0] = mode;//OBSSC_dots[1:0];
		end
		else begin
			sevenSegEnables = ~(mode[0]) ? 4'd0 : 4'b1111;
			sevenSegData = (~pButtons[3] ? MEM1_DataOut1[15:0] : MEM1_DataOut1[31:16]);
			sevenSegDots[3:2] = 2'b0;
			sevenSegDots[1:0] = mode;
		end
		
	end

endmodule
